//! Serde `Deserializer` module

use std::io::BufRead;

use serde::de::{self, DeserializeSeed};

use crate::{
    de::{Deserializer, escape::EscapedDeserializer},
    errors::serialize::DeError,
    events::Event,
};

/// A deserializer for `Attributes`
pub(crate) struct MapAccess<'a, R: BufRead> {
    de: &'a mut Deserializer<R>,
    tag: String,
}

impl<'a, R: BufRead> MapAccess<'a, R> {
    /// Create a new MapAccess
    pub fn new(de: &'a mut Deserializer<R>) -> Result<Self, DeError> {
        Ok(MapAccess {
            de,
            tag: String::new(),
        })
    }
}

impl<'a, 'de, R: BufRead> de::MapAccess<'de> for MapAccess<'a, R> {
    type Error = DeError;

    fn next_key_seed<K: DeserializeSeed<'de>>(
        &mut self,
        seed: K,
    ) -> Result<Option<K::Value>, Self::Error> {
        if let Some(Event::Start(_)) = self.de.peek()? {
            let decoder = self.de.reader.decoder();
            let tag = self.de.next_start(&mut Vec::new())?.unwrap();
            self.tag = String::from_utf8_lossy(tag.name()).to_string();
            if self.tag.ne("data") {
                return seed
                    .deserialize(EscapedDeserializer::new(
                        tag.local_name().to_owned(),
                        decoder,
                        false,
                    ))
                    .map(Some);
            }

            let attr = tag
                .attributes()
                .find(|a| match a {
                    Ok(attribute) => String::from_utf8_lossy(attribute.key).eq("name"),
                    _ => false,
                })
                .ok_or(DeError::Custom("No name attribute of data tag".into()))?
                .map_err(|_| DeError::Custom("No name attribute of data tag".into()))?;

            if let Some(_) = self.de.next_start(&mut Vec::new()).unwrap_or(None) {
                return seed
                    .deserialize(EscapedDeserializer::new(
                        Vec::from(attr.value),
                        decoder,
                        false,
                    ))
                    .map(Some);
            }
        }
        Ok(None)
    }

    fn next_value_seed<K: DeserializeSeed<'de>>(
        &mut self,
        seed: K,
    ) -> Result<K::Value, Self::Error> {
        let res = seed.deserialize(&mut *self.de);
        self.de.read_to_end(self.tag.as_ref())?;
        res
    }
}
